<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common"
	xmlns:dyn="http://exslt.org/dynamic" xmlns:test="http://xsltut.googlecode.com" xmlns:x="http://www.dummy.com"
	version="1.0" extension-element-prefixes="exsl">
	<xsl:namespace-alias stylesheet-prefix="x" result-prefix="xsl"/>
	<xsl:param name="path"/>
	<xsl:param name="filename">
		<xsl:call-template name="getFilename">
			<xsl:with-param name="path" select="$path"/>
		</xsl:call-template>
	</xsl:param>
	<xsl:variable name="totalTest" select="count( //test:test )"/>
	<xsl:template name="getFilename">
		<xsl:param name="path"/>
		<xsl:choose>
			<xsl:when test="contains( $path, '\' )">
				<xsl:call-template name="getFilename">
					<xsl:with-param name="path" select="substring-after( $path, '\' )"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="substring-before( $path, '.' )"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	<xsl:template match="//test:testCase">
		<xsl:variable name="testCaseName" select="@name"/>
		<xsl:variable name="inputSchema" select="@inputSchema"/>
		<xsl:variable name="outputSchema" select="@outputSchema"/>
		<!-- write validate -->
		<exsl:document href="__xsltut_validate.bat" method="text" indent="yes">
			<xsl:for-each select="test:test">
				<xsl:variable name="testId" select="generate-id(.)"/>
				<xsl:variable name="testIndex">
					<xsl:for-each select="//test:test">
						<xsl:if test="generate-id(.) = $testId">
							<xsl:value-of select="position()"/>
						</xsl:if>
					</xsl:for-each>
				</xsl:variable>
				<xsl:variable name="testname" select="concat( $testCaseName, '-', @name )"/>
				<xsl:variable name="indexedTestname"
					select="concat( format-number( $testIndex, 'T0000' ), '-', $testCaseName, '-', @name )"/>
				<xsl:variable name="inputFile" select="concat( '__xsltut_', $indexedTestname, '.input.xml' )"/>
				<xsl:variable name="expectFile" select="concat( '__xsltut_', $indexedTestname, '.expect.xml' )"/>
				<xsl:variable name="resultFile" select="concat( '__xsltut_', $indexedTestname, '.result.xml' )"/>
				<xsl:call-template name="putValidate">
					<xsl:with-param name="schema" select="$inputSchema"/>
					<xsl:with-param name="file" select="$inputFile"/>
				</xsl:call-template>
				<xsl:call-template name="putValidate">
					<xsl:with-param name="schema" select="$outputSchema"/>
					<xsl:with-param name="file" select="$expectFile"/>
				</xsl:call-template>
				<xsl:call-template name="putValidate">
					<xsl:with-param name="schema" select="$outputSchema"/>
					<xsl:with-param name="file" select="$resultFile"/>
				</xsl:call-template>
			</xsl:for-each>
		</exsl:document>
		<!-- write util -->
		<exsl:document href="__xsltut_util.xsl" method="xml" encoding="utf-8" indent="yes">
			<x:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:dyn="http://exslt.org/dynamic"
				xmlns:test="http://xsltut.googlecode.com" version="1.0" extension-element-prefixes="exsl">
				<x:output method="xml" encoding="UTF-8"/>
				<x:template name="putXPath">
					<x:param name="node"/>
					<x:choose>
						<x:when test="string-length( name( $node ) ) > 0">
							<x:for-each select="$node">
								<x:for-each select="ancestor-or-self::*">
									<x:variable name="curNode" select="generate-id(.)"/>
									<x:variable name="curNodeName" select="name(.)"/>
									<x:text>/</x:text>
									<x:value-of select="name()"/>
									<x:if test="count( ../*[ name() = $curNodeName ] ) > 1">
										<x:for-each select="../*[ name() = $curNodeName ]">
											<x:if test="generate-id(.) = $curNode">
												<x:value-of select="concat( '[', position(), ']' )"/>
											</x:if>
										</x:for-each>
									</x:if>
								</x:for-each>
								<xsl:text>|</xsl:text>
							</x:for-each>
						</x:when>
						<x:otherwise>No Path|</x:otherwise>
					</x:choose>
				</x:template>
				<x:template name="deepNotEqual">
					<x:param name="n1"/>
					<x:param name="n2"/>
					<x:param name="type"/>
					<x:param name="deep" select="true()"/>
					<x:param name="print"/>
					<x:variable name="t1" select="exsl:object-type( $n1 )"/>
					<x:variable name="t2" select="exsl:object-type( $n2 )"/>
					<x:choose>
						<!-- equal type -->
						<x:when test="$t1 = $t2">
							<x:choose>
								<!-- equal node-set type-->
								<x:when test="$t1 = 'node-set'">
									<x:variable name="nodeCnt1" select="count( * )"/>
									<x:variable name="nodeCnt2" select="count( * )"/>
									<x:choose>
										<x:when test="$n1 and $n2 and $nodeCnt1 = $nodeCnt2">
											<x:variable name="name1" select="name( $n1 )"/>
											<x:variable name="name2" select="name( $n2 )"/>
											<x:variable name="text1" select="normalize-space( $n1/text() )"/>
											<x:variable name="text2" select="normalize-space( $n2/text() )"/>
											<x:variable name="attrCnt1" select="count( $n1/@* )"/>
											<x:variable name="attrCnt2" select="count( $n2/@* )"/>
											<x:variable name="childCnt1" select="count( $n1/* )"/>
											<x:variable name="childCnt2" select="count( $n2/* )"/>
											<x:choose>
												<x:when
													test="( $name1 = $name2 ) and ( $text1 = $text2 ) and ( $attrCnt1 = $attrCnt2 ) and ( $childCnt1 = $childCnt2 )">
													<x:choose>
														<!-- same attributes -->
														<x:when test="not( $n1/@*[ not( . = $n2/@* ) ] )">
															<x:choose>
																<!-- need recurse -->
																<x:when test="$deep = 'true' and $childCnt1 &gt; 0">
																	<x:variable name="notEqualPaths">
																		<x:for-each select="$n1/*">
																			<x:variable name="c1" select="."/>
																			<x:variable name="no" select="position()"/>
																			<x:for-each select="$n2/*[$no]">
																				<x:variable name="c2" select="."/>
																				<x:call-template name="deepNotEqual">
																					<x:with-param name="n1" select="$c1"/>
																					<x:with-param name="n2" select="$c2"/>
																				</x:call-template>
																			</x:for-each>
																		</x:for-each>
																	</x:variable>
																	<x:if test="string-length( $notEqualPaths ) &gt; 0">
																		<x:value-of select="$notEqualPaths"/>
																	</x:if>
																</x:when>
																<!-- no need recurse -->
																<x:otherwise>
																	<x:if test="not( normalize-space( $n1 ) = normalize-space( $n2 ) )">
																		<x:call-template name="putXPath">
																			<x:with-param name="node" select="$n1"/>
																		</x:call-template>
																	</x:if>
																</x:otherwise>
															</x:choose>
														</x:when>
														<x:otherwise>
															<x:call-template name="putXPath">
																<x:with-param name="node" select="$n1"/>
															</x:call-template>
														</x:otherwise>
													</x:choose>
												</x:when>
												<x:otherwise>
													<x:call-template name="putXPath">
														<x:with-param name="node" select="$n1"/>
													</x:call-template>
												</x:otherwise>
											</x:choose>
										</x:when>
										<x:otherwise>
											<x:call-template name="putXPath">
												<x:with-param name="node" select="$n1"/>
											</x:call-template>
										</x:otherwise>
									</x:choose>
								</x:when>
								<!-- equal, but not node-set type-->
								<x:otherwise>
									<xsl:call-template name="putValueNotEqual"/>
								</x:otherwise>
							</x:choose>
						</x:when>
						<!-- not equal type -->
						<x:otherwise>
							<xsl:call-template name="putValueNotEqual"/>
						</x:otherwise>
					</x:choose>
				</x:template>
			</x:stylesheet>
		</exsl:document>
		<!-- for each test -->
		<xsl:for-each select="test:test">
			<xsl:variable name="testId" select="generate-id(.)"/>
			<xsl:variable name="testIndex">
				<xsl:for-each select="//test:test">
					<xsl:if test="generate-id(.) = $testId">
						<xsl:value-of select="position()"/>
					</xsl:if>
				</xsl:for-each>
			</xsl:variable>
			<xsl:variable name="testname" select="concat( $testCaseName, '-', @name )"/>
			<xsl:variable name="indexedTestname"
				select="concat( format-number( $testIndex, 'T0000' ), '-', $testCaseName, '-', @name )"/>
			<xsl:variable name="inputSelect">
				<xsl:choose>
					<xsl:when test="test:input/@select">
						<xsl:value-of select="test:input/@select"/>
					</xsl:when>
					<xsl:otherwise>/*[1]</xsl:otherwise>
				</xsl:choose>
			</xsl:variable>
			<!-- write input -->
			<exsl:document href="__xsltut_{$indexedTestname}.input.xml" method="xml" encoding="utf-8" indent="yes">
				<xsl:choose>
					<xsl:when test="test:input">
						<xsl:for-each select="test:input">
							<xsl:apply-templates/>
						</xsl:for-each>
					</xsl:when>
					<xsl:otherwise>
						<dummy/>
					</xsl:otherwise>
				</xsl:choose>
			</exsl:document>
			<!-- write expect -->
			<exsl:document href="__xsltut_{$indexedTestname}.expect.xml" method="xml" encoding="utf-8" indent="yes">
				<xsl:for-each select="test:expect">
					<xsl:apply-templates/>
				</xsl:for-each>
			</exsl:document>
			<!-- write test -->
			<exsl:document href="__xsltut_{$indexedTestname}.xsl" method="xml" encoding="utf-8" indent="yes">
				<x:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:dyn="http://exslt.org/dynamic"
					xmlns:test="http://xsltut.googlecode.com" version="1.0" extension-element-prefixes="exsl">
					<x:import href="__xsltut_util.xsl"/>
					<xsl:if test="test:xslt">
						<x:import href="test.xsl"/>
					</xsl:if>
					<x:output method="text" encoding="UTF-8"/>
					<xsl:if test="test:expect">
						<x:variable name="expect">
							<xsl:for-each select="test:expect">
								<xsl:copy-of select="*"/>
							</xsl:for-each>
						</x:variable>
					</xsl:if>
					<x:template match="/">
						<x:variable name="failed">
							<xsl:choose>
								<xsl:when test="test:xslt">
									<x:variable name="result">
										<xsl:for-each select="test:xslt/*">
											<xsl:copy-of select="."/>
										</xsl:for-each>
									</x:variable>
									<x:call-template name="deepNotEqual">
										<x:with-param name="n1" select="$result"/>
										<x:with-param name="n2" select="$expect"/>
										<xsl:if test="test:expect/@type">
											<xsl:for-each select="test:expect">
												<x:with-param name="type">
													<xsl:value-of select="@type"/>
												</x:with-param>
											</xsl:for-each>
										</xsl:if>
									</x:call-template>
								</xsl:when>
								<xsl:otherwise>
									<x:call-template name="deepNotEqual">
										<xsl:variable name="resultFile" select="concat( '__xsltut_', $indexedTestname, '.result.xml' )"/>
										<xsl:variable name="expectFile" select="concat( '__xsltut_', $indexedTestname, '.expect.xml' )"/>
										<x:with-param name="n1">
											<xsl:attribute name="select">document( '<xsl:value-of select="$resultFile"/>')<xsl:value-of
													select="$inputSelect"/></xsl:attribute>
										</x:with-param>
										<x:with-param name="n2">
											<xsl:attribute name="select">document( '<xsl:value-of select="$expectFile"
											/>')/*[1]</xsl:attribute>
										</x:with-param>
									</x:call-template>
								</xsl:otherwise>
							</xsl:choose>
						</x:variable>
						<xsl:variable name="output"
							select="concat( '  ', $testIndex, ' / ', $totalTest, '  :  Testing   &quot;', $testname, '&quot;' )"/>
						<xsl:value-of select="$output"/>
						<xsl:call-template name="putSpaces">
							<xsl:with-param name="count" select="60 - string-length( $output )"/>
						</xsl:call-template>
						<x:choose>
							<x:when test="string-length( normalize-space( $failed ) ) > 0">
								<x:value-of select="concat( '* Failed  ( ', substring-before( $failed, '|' ), ' )&#10;' )"/>
							</x:when>
							<x:otherwise>
								<x:text> Passed&#10;</x:text>
							</x:otherwise>
						</x:choose>
					</x:template>
				</x:stylesheet>
			</exsl:document>
		</xsl:for-each>
	</xsl:template>
	<xsl:template name="putValidate">
		<xsl:param name="schema"/>
		<xsl:param name="file"/>
		<xsl:if test="string-length( $schema ) > 0">
			<xsl:choose>
				<xsl:when test="contains( $schema, '.rng' )">
					<xsl:value-of select="concat( '%XMLLINT% --noout --xinclude --relaxng ', $schema, ' ', $file )"/>
				</xsl:when>
				<xsl:when test="contains( $schema, '.xsd' )">
					<xsl:value-of select="concat( '%XMLLINT% --noout --xinclude --schema ', $schema, ' ', $file )"/>
				</xsl:when>
			</xsl:choose>
			<xsl:text>&#10;</xsl:text>
		</xsl:if>
	</xsl:template>
	<xsl:template name="putValueNotEqual">
		<x:choose>
			<x:when test="$type = 'string'">
				<x:if test="not( normalize-space( $n1 ) = normalize-space( $n2 ) )">
					<x:call-template name="putXPath">
						<x:with-param name="node" select="$n1"/>
					</x:call-template>
				</x:if>
			</x:when>
			<x:when test="$type = 'number'">
				<x:if test="not( number( $n1 ) = number( $n2 ) )">
					<x:call-template name="putXPath">
						<x:with-param name="node" select="$n1"/>
					</x:call-template>
				</x:if>
			</x:when>
			<x:when test="$type = 'boolean'">
				<x:if test="not( boolean( $n1 ) = boolean( $n2 ) )">
					<x:call-template name="putXPath">
						<x:with-param name="node" select="$n1"/>
					</x:call-template>
				</x:if>
			</x:when>
			<x:otherwise>
				<x:call-template name="putXPath">
					<x:with-param name="node" select="$n1"/>
				</x:call-template>
			</x:otherwise>
		</x:choose>
	</xsl:template>
	<xsl:template name="putSpaces">
		<xsl:param name="count"/>
		<xsl:if test="$count &gt; 0">
			<xsl:text> </xsl:text>
			<xsl:call-template name="putSpaces">
				<xsl:with-param name="count" select="$count - 1"/>
			</xsl:call-template>
		</xsl:if>
	</xsl:template>
	<!-- xsltut element templates -->
	<xsl:template match="test:ref">
		<xsl:variable name="refName" select="@name"/>
		<xsl:for-each select="ancestor::test:testCase/test:define[ @name = $refName ]">
			<xsl:copy-of select="*"/>
		</xsl:for-each>
	</xsl:template>
	<xsl:template match="test:input">
		<xsl:choose>
			<!-- node-set -->
			<xsl:when test="not( @type ) or @type = 'node-set'">
				<xsl:copy-of select="*"/>
			</xsl:when>
			<!-- value -->
			<xsl:otherwise>
				<xsl:element name="__xsltut_value">
					<xsl:if test="@type">
						<xsl:attribute name="type">
							<xsl:value-of select="@type"/>
						</xsl:attribute>
					</xsl:if>
					<xsl:value-of select="."/>
				</xsl:element>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	<xsl:template match="test:expect">
		<xsl:choose>
			<!-- node-set -->
			<xsl:when test="not( @type ) or @type = 'node-set'">
				<xsl:copy-of select="*"/>
			</xsl:when>
			<!-- value -->
			<xsl:otherwise>
				<xsl:element name="__xsltut_value">
					<xsl:if test="@type">
						<xsl:attribute name="type">
							<xsl:value-of select="@type"/>
						</xsl:attribute>
					</xsl:if>
					<xsl:value-of select="."/>
				</xsl:element>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	<xsl:template match="*">
		<xsl:copy>
			<xsl:for-each select="@*">
				<xsl:copy/>
			</xsl:for-each>
			<xsl:apply-templates/>
		</xsl:copy>
	</xsl:template>
	<xsl:template match="text()">
		<xsl:copy/>
	</xsl:template>
</xsl:stylesheet>
